/*
const char* JsonAstBuilder2::BuildProgram(FunctionLiteral* program) { PrintF("===================== Json2::BuildProg\n");
  Init();
  Visit(program);
  Print("\n");
  return Output();
}


void JsonAstBuilder2::AddAttributePrefix(const char* name) {
  if (attributes()->is_used()) {
    Print(",\n");
    PrintIndented("\"");
  } else {
    Print("\"");
  }
  Print("%s\":", name);
  attributes()->use();
}


void JsonAstBuilder2::AddAttribute(const char* name, Handle<String> value) {
  SmartPointer<char> value_string = value->ToCString();
  AddAttributePrefix(name);
  Print("\"%s\"", *value_string);
}


void JsonAstBuilder2::AddAttribute(const char* name, const char* value) {
  AddAttributePrefix(name);
  Print("\"%s\"", value);
}


void JsonAstBuilder2::AddAttribute(const char* name, int value) {
  AddAttributePrefix(name);
  Print("%d", value);
}


void JsonAstBuilder2::AddAttribute(const char* name, bool value) {
  AddAttributePrefix(name);
  Print(value ? "true" : "false");
}
*/

//     AddAttribute(AstTokenAttribute::String(AstTokenAttribute::kOp), Token::String(expr->op()));
#define ATTR_OP AddAttribute(AstTokenAttribute::String(AstTokenAttribute::kOp), Token::String(expr->op()));

const char* JsonAstBuilder2::BuildProgram(FunctionLiteral* program) {
  /*
  Init();
  Visit(program);
  Print("\n");
  return Output();
  */
  Init();
  { /*
    IndentedScope indent("Program");
    PrintLiteralIndented("NAME", program->name(), true);
    PrintLiteralIndented("INFERRED NAME", program->inferred_name(), true);
    PrintParameters(program->scope());
    PrintDeclarations(program->scope()->declarations());
    PrintStatements(program->body());
    */
  TagScope tag(this, AstTokenString(AstToken::kProgram));
  VisitStatements(program->body());
  }
  return Output();
}

void JsonAstBuilder2::VisitBlock(Block* stmt) {
  //TagScope tag(this, "Block");
  TagScope tag(this, AstTokenString(AstToken::kBlock));
  VisitStatements(stmt->statements());
}


void JsonAstBuilder2::VisitExpressionStatement(ExpressionStatement* stmt) {
  //TagScope tag(this, "ExpressionStatement");
  TagScope tag(this, AstTokenString(AstToken::kExpressionStatement));
  Visit(stmt->expression());
}


void JsonAstBuilder2::VisitEmptyStatement(EmptyStatement* stmt) {
  //TagScope tag(this, "EmptyStatement");
  TagScope tag(this, AstTokenString(AstToken::kEmptyStatement));
}


void JsonAstBuilder2::VisitIfStatement(IfStatement* stmt) {
  //TagScope tag(this, "IfStatement");
  TagScope tag(this, AstTokenString(AstToken::kIfStatement));
  Visit(stmt->condition());
  Visit(stmt->then_statement());
  Visit(stmt->else_statement());
}


void JsonAstBuilder2::VisitContinueStatement(ContinueStatement* stmt) {
  //TagScope tag(this, "ContinueStatement");
  TagScope tag(this, AstTokenString(AstToken::kContinueStatement));
}


void JsonAstBuilder2::VisitBreakStatement(BreakStatement* stmt) {
  //TagScope tag(this, "BreakStatement");
  TagScope tag(this, AstTokenString(AstToken::kBreakStatement));
}


void JsonAstBuilder2::VisitReturnStatement(ReturnStatement* stmt) {
  //TagScope tag(this, "ReturnStatement");
  TagScope tag(this, AstTokenString(AstToken::kReturnStatement));
  Visit(stmt->expression());
}


void JsonAstBuilder2::VisitWithEnterStatement(WithEnterStatement* stmt) {
  //TagScope tag(this, "WithEnterStatement");
  TagScope tag(this, AstTokenString(AstToken::kWithEnterStatement));
  Visit(stmt->expression());
}


void JsonAstBuilder2::VisitWithExitStatement(WithExitStatement* stmt) {
  //TagScope tag(this, "WithExitStatement");
  TagScope tag(this, AstTokenString(AstToken::kWithExitStatement));
}


void JsonAstBuilder2::VisitSwitchStatement(SwitchStatement* stmt) {
  //TagScope tag(this, "SwitchStatement");
  TagScope tag(this, AstTokenString(AstToken::kSwitchStatement));
}


void JsonAstBuilder2::VisitDoWhileStatement(DoWhileStatement* stmt) {
  //TagScope tag(this, "DoWhileStatement");
  TagScope tag(this, AstTokenString(AstToken::kDoWhileStatement));
  Visit(stmt->body());
  Visit(stmt->cond());
}


void JsonAstBuilder2::VisitWhileStatement(WhileStatement* stmt) {
  //TagScope tag(this, "WhileStatement");
  TagScope tag(this, AstTokenString(AstToken::kWhileStatement));
  Visit(stmt->cond());
  Visit(stmt->body());
}


void JsonAstBuilder2::VisitForStatement(ForStatement* stmt) {
  //TagScope tag(this, "ForStatement");
  TagScope tag(this, AstTokenString(AstToken::kForStatement));
  if (stmt->init() != NULL) Visit(stmt->init());
  if (stmt->cond() != NULL) Visit(stmt->cond());
  Visit(stmt->body());
  if (stmt->next() != NULL) Visit(stmt->next());
}


void JsonAstBuilder2::VisitForInStatement(ForInStatement* stmt) {
  //TagScope tag(this, "ForInStatement");
  TagScope tag(this, AstTokenString(AstToken::kForInStatement));
  Visit(stmt->each());
  Visit(stmt->enumerable());
  Visit(stmt->body());
}


void JsonAstBuilder2::VisitTryCatchStatement(TryCatchStatement* stmt) {
  //TagScope tag(this, "TryCatchStatement");
  TagScope tag(this, AstTokenString(AstToken::kTryCatchStatement));
  Visit(stmt->try_block());
  Visit(stmt->catch_var());
  Visit(stmt->catch_block());
}


void JsonAstBuilder2::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
  //TagScope tag(this, "TryFinallyStatement");
  TagScope tag(this, AstTokenString(AstToken::kTryFinallyStatement));
  Visit(stmt->try_block());
  Visit(stmt->finally_block());
}


void JsonAstBuilder2::VisitDebuggerStatement(DebuggerStatement* stmt) {
  TagScope tag(this, "DebuggerStatement");
}


void JsonAstBuilder2::VisitFunctionLiteral(FunctionLiteral* expr) {
  //TagScope tag(this, "FunctionLiteral");
  TagScope tag(this, AstTokenString(AstToken::kFunctionLiteral));
  {
    AttributesScope attributes(this);
    AddAttribute("name", expr->name());
  }
  VisitDeclarations(expr->scope()->declarations());
  VisitStatements(expr->body());
}


void JsonAstBuilder2::VisitFunctionBoilerplateLiteral(
    FunctionBoilerplateLiteral* expr) {
  //TagScope tag(this, "FunctionBoilerplateLiteral");
  TagScope tag(this, AstTokenString(AstToken::kFunctionBoilerplateLiteral));
}


void JsonAstBuilder2::VisitConditional(Conditional* expr) {
  //TagScope tag(this, "Conditional");
  TagScope tag(this, AstTokenString(AstToken::kConditional));
}


void JsonAstBuilder2::VisitSlot(Slot* expr) {
  //TagScope tag(this, "Slot");
  TagScope tag(this, "----------- Slot");
  {
    AttributesScope attributes(this);
    switch (expr->type()) {
      case Slot::PARAMETER:
        AddAttribute("type", "PARAMETER");
        break;
      case Slot::LOCAL:
        AddAttribute("type", "LOCAL");
        break;
      case Slot::CONTEXT:
        AddAttribute("type", "CONTEXT");
        break;
      case Slot::LOOKUP:
        AddAttribute("type", "LOOKUP");
        break;
      case Slot::GLOBAL:
        AddAttribute("type", "GLOBAL");
        break;
    }
    AddAttribute("index", expr->index());
  }
}


void JsonAstBuilder2::VisitVariableProxy(VariableProxy* expr) {
 //TagScope tag(this, "VariableProxy");
  TagScope tag(this, AstTokenString(AstToken::kVariableProxy));

 AttributesScope attributes(this);
 AddAttribute("name", expr->name());

 Variable* var = expr->var();
 if (var != NULL) {
     AddAttribute("mode", Variable::Mode2String(var->mode()));
     if (var->rewrite() != NULL) {
       Visit(var->rewrite());
     }
 }
}


void JsonAstBuilder2::VisitLiteral(Literal* expr) {
  //TagScope tag(this, "Literal");
  TagScope tag(this, AstTokenString(AstToken::kLiteral));
  {
    AttributesScope attributes(this);
    Handle<Object> handle = expr->handle();
    if (handle->IsString()) {
      AddAttribute("handle", Handle<String>(String::cast(*handle)));
    } else if (handle->IsSmi()) {
      AddAttribute("handle", Smi::cast(*handle)->value());
    }
  }
}


void JsonAstBuilder2::VisitRegExpLiteral(RegExpLiteral* expr) {
  //TagScope tag(this, "RegExpLiteral");
  TagScope tag(this, AstTokenString(AstToken::kRegExpLiteral));
}


void JsonAstBuilder2::VisitObjectLiteral(ObjectLiteral* expr) {
  //TagScope tag(this, "ObjectLiteral");
  TagScope tag(this, AstTokenString(AstToken::kObjectLiteral));
}


void JsonAstBuilder2::VisitArrayLiteral(ArrayLiteral* expr) {
  //TagScope tag(this, "ArrayLiteral");
  TagScope tag(this, AstTokenString(AstToken::kArrayLiteral));
}


void JsonAstBuilder2::VisitCatchExtensionObject(CatchExtensionObject* expr) {
  //TagScope tag(this, "CatchExtensionObject");
  TagScope tag(this, AstTokenString(AstToken::kCatchExtensionObject));
  Visit(expr->key());
  Visit(expr->value());
}


void JsonAstBuilder2::VisitAssignment(Assignment* expr) {
  //TagScope tag(this, "Assignment");
  TagScope tag(this, AstTokenString(AstToken::kAssignment));
  {
    AttributesScope attributes(this);
    //AddAttribute("op", Token::Name(expr->op()));
    ATTR_OP
  }
  Visit(expr->target());
  Visit(expr->value());
}


void JsonAstBuilder2::VisitThrow(Throw* expr) {
  //TagScope tag(this, "Throw");
  TagScope tag(this, AstTokenString(AstToken::kThrow));
  Visit(expr->exception());
}


void JsonAstBuilder2::VisitProperty(Property* expr) {
  //TagScope tag(this, "Property");
  TagScope tag(this, AstTokenString(AstToken::kProperty));
  {
    AttributesScope attributes(this);
    AddAttribute("type", expr->is_synthetic() ? "SYNTHETIC" : "NORMAL");
  }
  Visit(expr->obj());
  Visit(expr->key());
}


void JsonAstBuilder2::VisitCall(Call* expr) {
  //TagScope tag(this, "Call");
  TagScope tag(this, AstTokenString(AstToken::kCall));
  Visit(expr->expression());
  VisitExpressions(expr->arguments());
}


void JsonAstBuilder2::VisitCallNew(CallNew* expr) {
  //TagScope tag(this, "CallNew");
  TagScope tag(this, AstTokenString(AstToken::kCallNew));
  Visit(expr->expression());
  VisitExpressions(expr->arguments());
}


void JsonAstBuilder2::VisitCallRuntime(CallRuntime* expr) {
  //TagScope tag(this, "CallRuntime");
  TagScope tag(this, "DONT SHOW --- CallRuntime");
  {
    AttributesScope attributes(this);
    AddAttribute("name", expr->name());
  }
  VisitExpressions(expr->arguments());
}


void JsonAstBuilder2::VisitUnaryOperation(UnaryOperation* expr) {
  //TagScope tag(this, "UnaryOperation");
  TagScope tag(this, AstTokenString(AstToken::kUnaryOperation));
  {
    AttributesScope attributes(this);
    AddAttribute("op", Token::Name(expr->op()));
  }
  Visit(expr->expression());
}


void JsonAstBuilder2::VisitCountOperation(CountOperation* expr) {
  //TagScope tag(this, "CountOperation");
  TagScope tag(this, AstTokenString(AstToken::kCountOperation));
  {
    AttributesScope attributes(this);
    AddAttribute("is_prefix", expr->is_prefix());
    AddAttribute("op", Token::Name(expr->op()));
  }
  Visit(expr->expression());
}


void JsonAstBuilder2::VisitBinaryOperation(BinaryOperation* expr) {
  //TagScope tag(this, "BinaryOperation2");
  TagScope tag(this, AstTokenString(AstToken::kBinaryOperation));
  {
    AttributesScope attributes(this);
    //AddAttribute("op", Token::Name(expr->op()));
    //AddAttribute("op", Token::String(expr->op()));
    //AddAttribute(AstTokenAttribute::String(AstTokenAttribute::kOp), Token::String(expr->op()));
    ATTR_OP
  }
  Visit(expr->left());
  Visit(expr->right());
}


void JsonAstBuilder2::VisitCompareOperation(CompareOperation* expr) {
  //TagScope tag(this, "CompareOperation");
  TagScope tag(this, AstTokenString(AstToken::kCompareOperation));
  {
    AttributesScope attributes(this);
    //AddAttribute("op", Token::Name(expr->op()));
    ATTR_OP
  }
  Visit(expr->left());
  Visit(expr->right());
}


void JsonAstBuilder2::VisitThisFunction(ThisFunction* expr) {
  //TagScope tag(this, "ThisFunction");
  TagScope tag(this, AstTokenString(AstToken::kThisFunction));
}


void JsonAstBuilder2::VisitDeclaration(Declaration* decl) {
  //TagScope tag(this, "Declaration");
  TagScope tag(this, "----- DON'T SHOW Declaration");
  {
    AttributesScope attributes(this);
    AddAttribute("mode", Variable::Mode2String(decl->mode()));
  }
  Visit(decl->proxy());
  if (decl->fun() != NULL) Visit(decl->fun());
}

#undef ATTR_OP


